package cn.cool.middleware.biz_exception_retry.types.common.helper;

import cn.cool.middleware.biz_exception_retry.types.exception.BizExceptionRetryException;
import com.github.rholder.retry.*;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@Slf4j
public class BizMemoryRetryHelper {
    /**
     * 任务重试 helper
     * @param callable 需要被重试的任务
     * @param attemptedNumber 重试的次数
     * @param sleepTime 重试的间隔时间
     * @return
     * @param <T>
     */
    public static <T> T retry(final Callable<T> callable, int attemptedNumber, long sleepTime) {
        /**
         * <>https://github.com/rholder/guava-retrying</>
         * 基于 Guava retryer 构建重试器：发生异常时重试
         * 等待策略：每次请求间隔 sleepTime 毫秒
         * 停止策略：尝试请求 attemptedNumber 次
         */
        Retryer<T> retryer = RetryerBuilder.<T>newBuilder()
                .retryIfExceptionOfType(Throwable.class)
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.MILLISECONDS))
                .withStopStrategy(StopStrategies.stopAfterAttempt(attemptedNumber))
                .build();

        try {
            // 执行 callable 任务
            return retryer.call(callable);
        } catch (ExecutionException e) {
            log.error("BizMemoryRetryHelper catch executionException", e);
            throw new BizExceptionRetryException("catch executionException memory retry fail. ", e);
        } catch (RetryException e) {
            log.error("BizMemoryRetryHelper catch retryException", e);
            String message = e.getCause() == null ? "" : e.getCause().getMessage();
            throw new BizExceptionRetryException("catch executionException memory retry fail. "
                    + e.getMessage() + " bizExceptionMessage:" + message, e);
        }
    }

    /**
     * 任务重试 helper
     * @param callable 需要被重试的任务
     * @return
     * @param <T>
     */
    public static <T> T retry(final Callable<T> callable) {
        return retry(callable, 3, 1000);
    }
}
